﻿using System;
using System.Windows.Media;
using System.Windows;
using System.Globalization;
using System.Runtime.Serialization;
using System.Collections.Generic;

namespace WickedFlame.Core.Shapes
{
    //public delegate void ChangedEventHandler(object sender, EventArgs e);

    public abstract class VectorShape : DrawableShape// DrawingVisual
    {
        public VectorShape()
        {
        }

        /// <summary>
        /// Get handle point by 1-based number
        /// </summary>
        /// <param name="trackerNo"></param>
        /// <returns></returns>
        public abstract Point GetTracker(int trackerNo);

        /// <summary>
        /// Hit test
        /// </summary>
        /// <param name="point"></param>
        /// <returns>-1 no hit; 0 shape hit; >0 tracker number</returns>
        //public abstract int HitTestInt(Point point);
        public virtual int HitTestInt(Point point)
        {
            if (IsSelected)
            {
                List<int> trackers = null;
                // select all trackers that are near the hitpoint
                for (int i = 1; i <= TrackerCount; i++)
                {
                    if (GetTrackerRectangle(i).Contains(point))
                    {
                        if (trackers == null)
                            trackers = new List<int>();
                        trackers.Add(i);
                    }
                }

                if (trackers != null && trackers.Count >= 1)
                {
                    // get the tracker that is nearest to the hitpoint
                    int tmpTracker = trackers[0];
                    Point tmpPoint = GetTracker(tmpTracker);
                    
                    for(int i=0;i<trackers.Count;i++)
                    {
                        if (trackers[i] != tmpTracker)
                        {
                            var p = GetTracker(trackers[i]);
                            if (Distance(tmpPoint, point) > Distance(p, point))
                            {
                                tmpPoint = p;
                                tmpTracker = trackers[i];
                            }
                        }
                    }

                    return tmpTracker;
                }
            }

            if (PointInObject(point))
                return 0;

            return -1;
        }

        /// <summary>
        /// Test whether point is inside of the object
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        protected abstract bool PointInObject(Point point);

        /// <summary>
        /// Number of handles
        /// </summary>
        public abstract int TrackerCount { get; }

        /// <summary>
        /// Move tracker to the point
        /// </summary>
        /// <param name="point"></param>
        /// <param name="trackerNo"></param>
        public abstract void MoveTracker(Point point, int trackerNo);

        /// <summary>
        /// Move the shape
        /// </summary>
        /// <param name="deltaX"></param>
        /// <param name="deltaY"></param>
        public abstract void Move(double deltaX, double deltaY);

        /// <summary>
        /// Test whether object intersects with rectangle
        /// </summary>
        /// <param name="rectangle"></param>
        /// <returns></returns>
        public abstract bool IntersectsWith(Rect rectangle);

        /// <summary>
        /// Surounding rectangle of the shape
        /// </summary>
        public abstract Rect Bounds { get; }

        /// <summary>
        /// Draw tracker for selected shape.
        /// </summary>
        public abstract void DrawTracker(DrawingContext drawingContext, double scale);

        public abstract void MoveTracker(int tracker, double deltaX, double deltaY);

        /// <summary>
        /// Get handle rectangle by 1-based number
        /// </summary>
        /// <param name="trackerNo"></param>
        /// <returns></returns>
        public virtual Rect GetTrackerRectangle(int trackerNo)
        {
            Point point = GetTracker(trackerNo);
            return new Rect(point.X - 3, point.Y - 3, 7, 7);
        }

        /// <summary>
        /// Get cursor for the handle
        /// </summary>
        /// <param name="trackerNo"></param>
        /// <returns></returns>
        public virtual System.Windows.Input.Cursor GetTrackerCursor(int trackerNo)
        {
            return System.Windows.Input.Cursors.Arrow;
        }

        public override bool IsSelected
        {
            get
            {
                return base.IsSelected;
            }
            set
            {
                if (!value)
                    UnselectAllTrackers();
                base.IsSelected = value;
            }
        }

        private int _selectedTracker = 0;
        public int SelectedTracker
        {
            get
            {
                return _selectedTracker;
            }
            private set
            {
                _selectedTracker = value;
            }
        }

        public virtual void SelectTracker(int tracker)
        {
            SelectedTracker = tracker;
        }

        public virtual void UnselectAllTrackers()
        {
            SelectedTracker = 0;
        }

        #region Static helper classes

        public static double Distance(Point point1, Point point2)
        {
            //C^2=a^2+b^2
            double xdist = 0.0;
            if (point1.X > point2.X)
                xdist = point1.X - point2.X;
            else
                xdist = point2.X - point1.X;

            double ydist = 0.0;
            if (point1.Y > point2.Y)
                ydist = point1.Y - point2.Y;
            else
                ydist = point2.Y - point1.Y;

            //C^2=a^2+b^2
            return Math.Sqrt((ydist * ydist) + (xdist * xdist));
        }

        #endregion
    }
}
